package org.checkboo.hopefullyengine.inversekinematics;

import java.util.LinkedList;

import org.checkboo.math.Matrix44f;

public class Skeleton {
	
	private Bone root;
	private LinkedList<Bone> bones = new LinkedList<Bone>();
	private LinkedList<Animation> animations;
	
	private int lastKeyFrame = -1;

	public Bone getRoot() {
		return root;
	}

	public void setRoot(Bone root) {
		this.root = root;
		this.root.setTotalTransform(this.root.getLocalTransform());
		this.root.getDefaultTransform();
	}

	public LinkedList<Bone> getBones() {
		return bones;
	}

	public void setBones(LinkedList<Bone> bones) {
		this.bones = bones;
	}
	
	public void initSkeleton(){
		initBones(root);
	}
	
	private void initBones(Bone bone){
		Matrix44f total;
		for(Bone child : bone.getChildren()){
			total = new Matrix44f();
			bone.getDefaultTransform().multiplyRes(child.getDefaultTransform(), total);
			child.setDefaultTransform(total);
			initBones(child);
		}
	}
	
	public Bone getBoneByName(String name){
		for(Bone b : this.bones){
			if(b.getName().equalsIgnoreCase(name))
				return b;
		}
		return null;
	}
	
	public Bone getBoneByID(int id){
		for(Bone b : this.bones){
			if(b.getId() == id)
				return b;
		}
		return null;
	}

	public LinkedList<Animation> getAnimations() {
		return animations;
	}
	
	public Animation getAnimationByName(String name){
		for(Animation a : this.animations){
			if(a.getName().equalsIgnoreCase(name))
				return a;
		}
		return null;
	}

	public void setAnimations(LinkedList<Animation> animations) {
		this.animations = animations;
	}
	
	public void updatePose(Animation animation){
		KeyFrame tmpKeyFrame = new KeyFrame(0);
		for(Track t : animation.getTracks()){
			this.lastKeyFrame = lastKeyFrame+1>=t.getKeyFrames().size() ? 0 : lastKeyFrame+1;
			tmpKeyFrame = t.getKeyFrames().get(lastKeyFrame);
			getBoneByName(t.getBone()).setLocalTranslation(tmpKeyFrame.getTranslation());
			getBoneByName(t.getBone()).setLocalRotation(tmpKeyFrame.getRotation());
			getBoneByName(t.getBone()).setLocalScale(tmpKeyFrame.getScale());
		}
		compileSkeleton();
	}
		
	public void compileSkeleton(){
		this.root.getCompleteTransform().set(this.root.getLocalTransform());
		compileBone(this.root);
	}
	
	public void compileBone(Bone bone){
		Matrix44f total = new Matrix44f();;
		for(Bone b : bone.getChildren()){
			bone.getCompleteTransform().multiplyRes(b.getLocalTransform(), total);
			b.getCompleteTransform().set(total);
			compileBone(b);
		}
	}
	
	public void reset(){
		for(Bone b : this.bones){
			b.reset();
		}
	}
}